#include "CMarco.h"
#include <stdlib.h>
#include <time.h>

//animate rate
//
#define FPS_ACTION 40	
#define FPS_STAND 8
#define FPS_JUMP 40

//verlocity of main character
//
#define VERLOCITY_X_RUN				0.5f			//Marco's verlocity when running
#define VERLOCITY_X_CROUCH_MOVE		0.15f			//marco's verlocity when moving in crouch status
#define VERLOCITY_X_JUMP			0.2f				//marco's verlocity when jump
#define VERLOCITY_Y_JUMP			-1.8f
#define VERLOCITY_X_JUMP_FAR		0.8f

#define MAX_HIGHT_JUMP	600-150-80-60

#define GROUND 600-240
//the direction of main character
//
#define RIGHT	0
#define LEFT	1

//sprite width and height
//
#define SPRITEWIDTH		77
#define SPRITEHEIGHT	100

//image position in a sprite
//
#define X	4*7
#define Y	11*7

//total bullet
#define BULLET_TOTAL 8

//file path of the sprite
//
#define BODY_CROUCH_FILE			"Body_Crouch_77x100_4_8.png"
#define BODY_CROUCH_CATCH_FLY_FILE	"Body_Crouch_Catch_Fly_77x100_8_16.png"
#define BODY_CROUCH_CUT_HORIZONTAL_FILE "Body_Crouch_Cut_Horizontal_77x100_6_12.png"
#define BODY_CROUCH_CUT_VERTICAL_FILE	"Body_Cut_Vertical_77x100_7_14.png"
#define BODY_CROUCH_MOVE_FILE			"Body_Crouch_Move_77x100_11_22.png"
#define BODY_CROUCH_SHOT_FILE				"Body_Crouch_Shot_77x100_10_20.png"
#define	BODY_CROUCH_THROW_GRENADE_FILE "Body_Crouch_Throw_Grenade_77x100_6_12.png"

#define BODY_CUT_HORIZONTAL_FILE	"Body_Cut_Horizontal_77x100_6_12.png"
#define BODY_CUT_VERTICAL_FILE		"Body_Cut_Vertical_77x100_6_12.png"
#define BODY_DRINK_FILE				"Body_Drink_77x100_8_16.png"
#define BODY_JUMP_FAR_FILE			"Body_Jump_Far_77x100_6_12.png"
#define BODY_JUMP_UP_FILE			"Body_Jump_Up_77x100_6_12.png"
#define BODY_RELOAD_FILE			"Body_Reload_77x100_18_36.png"
#define BODY_RUN_FILE				"Body_Run_77x100_12_24.png"
#define BODY_SCRATCH_NOSE_FILE		"Body_Scratch_Nose_77x100_17_34.png"
#define BODY_SHOT_FILE				"Body_Shot_77x100_10_20.png"
#define BODY_SHOT_DOWN_FILE			"Body_Shot_Down_77x100_7_14.png"
#define BODY_SHOT_UP_FILE			"Body_Shot_Up_77x100_18_36.png"
#define BODY_SLEEP_FILE				"Body_Sleep_77x100_10_20.png"
#define BODY_STAND_FILE				"Body_Stand_77x100_4_8.png"
#define BODY_THROW_GRENADE_FILE		"Body_Throw_Grenade_77x100_5_10.png"
#define BODY_TIRED_FILE				"Body_Tired_77x100_18_36.png"

#define LEG_JUMP_FAR_FILE			"Leg_Jump_Far_77x100_6_12.png"
#define LEG_JUMP_UP_FILE			"Leg_Jump_Up_77x100_1_2.png"
#define LEG_RUN_FILE				"Leg_Run_77x100_18_36.png"
#define LEG_STAND_ON_FILE			"Leg_Stand_77x100_1_2.png"

//number of body sprite
//
#define BODY_SPRITES	22

//number of leg sprite
#define LEG_SPRITES		4 + 1

//the index determine which body and leg will be render
//
#define BODY_JUMP_FAR		0
#define BODY_JUMP_UP		1
#define BODY_STAND			2
#define BODY_RUN			3

#define BODY_CROUCH					4
#define BODY_CROUCH_CATCH_FLY		5	
#define BODY_CROUCH_CUT_HORIZONTAL	6
#define BODY_CROUCH_CUT_VERTICAL	7
#define BODY_CROUCH_MOVE			8
#define BODY_CROUCH_SHOT			9
#define BODY_CROUCH_THROW_GRENADE	10

#define	BODY_CUT_HORIZONTAL 11	
#define	BODY_CUT_VERTICAL	12
#define BODY_SHOT			13
#define BODY_SHOT_DOWN		14
#define	BODY_SHOT_UP		15
#define	BODY_THROW_GRENADE	16

#define BODY_DRINK			17
#define BODY_SCRATCH_NOSE	18
#define BODY_SLEEP			19
#define BODY_TIRED			20
#define BODY_RELOAD			21

#define LEG_JUMP_FAR		1
#define LEG_JUMP_UP			2
#define	LEG_RUN				3
#define LEG_STAND			4

//this constant use to put the character to relax status by generate a index randomly
//
#define RELAX_START_INDEX	17
#define RELAX_END_INDEX		21	
//------------------------------------**********************************************-----------------------------------------

CMarco::CMarco (LPD3DXSPRITE SpriteHandler, float fScale, CQuadTree* q) 
{
	_mquadtree = q;
	m_nposX = 0;
	m_nAndr = 10;
	m_nposY = 0;

	mi_Direction = 0;
	m_nId = 1;
	m_nbulletIndex = 0;

	mi_AnimateRate = FPS_ACTION;

	mf_vx = 0;
	mf_vy =	0;

	mf_Scale = fScale;

	mi_BodyIndex	= BODY_STAND;
	mi_LegIndex		= LEG_STAND;	

	mb_IsAction		= false;
	mb_IsRelax		= false;
	mb_IsJump		= false;
	mb_ShotContinue = false;

	m_Sprite	=	new CSprite[BODY_SPRITES];
	Marco_Leg	=	new CSprite[LEG_SPRITES];

	mb_IsShot = false;
	
	for(int i = 0; i < BULLET_TOTAL; i++)
	{
		Bullet[i] = new CPistol(SpriteHandler, fScale);
		mb_isShot[i] = false;
	}

	loadSprite(SpriteHandler);

	Stand();
	setRect();
}

CMarco::~CMarco ()
{
	m_Sprite	= NULL;
	Marco_Leg	= NULL;
}

void CMarco::loadSprite(LPD3DXSPRITE SpriteHandler)
{
	m_Sprite[BODY_CROUCH].CreateSprite(			SpriteHandler, BODY_CROUCH_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 4, 8,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_CROUCH_CATCH_FLY].CreateSprite(	SpriteHandler, BODY_CROUCH_CATCH_FLY_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 8, 16,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_CROUCH_CUT_HORIZONTAL].CreateSprite(	SpriteHandler, BODY_CROUCH_CUT_HORIZONTAL_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_CROUCH_CUT_VERTICAL].CreateSprite(		SpriteHandler, BODY_CROUCH_CUT_VERTICAL_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 7, 14,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_CROUCH_MOVE].CreateSprite(				SpriteHandler, BODY_CROUCH_MOVE_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 11, 22,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_CROUCH_SHOT].CreateSprite(				SpriteHandler, BODY_CROUCH_SHOT_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 10, 20, mf_Scale, D3DCOLOR_XRGB(255,255,255));	
	m_Sprite[BODY_CROUCH_THROW_GRENADE].CreateSprite(		SpriteHandler, BODY_CROUCH_THROW_GRENADE_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255));

	m_Sprite[BODY_CUT_HORIZONTAL].CreateSprite(	SpriteHandler, BODY_CUT_HORIZONTAL_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_CUT_VERTICAL].CreateSprite(		SpriteHandler, BODY_CUT_VERTICAL_FILE,		SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_DRINK].CreateSprite(			SpriteHandler, BODY_DRINK_FILE,				SPRITEWIDTH, SPRITEHEIGHT, 8, 16,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_JUMP_FAR].CreateSprite(			SpriteHandler, BODY_JUMP_FAR_FILE,			SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_JUMP_UP].CreateSprite(			SpriteHandler, BODY_JUMP_UP_FILE,			SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_RELOAD].CreateSprite(			SpriteHandler, BODY_RELOAD_FILE,			SPRITEWIDTH, SPRITEHEIGHT, 18, 36,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_RUN].CreateSprite(				SpriteHandler, BODY_RUN_FILE,				SPRITEWIDTH, SPRITEHEIGHT, 12, 24,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_SCRATCH_NOSE].CreateSprite(		SpriteHandler, BODY_SCRATCH_NOSE_FILE,		SPRITEWIDTH, SPRITEHEIGHT, 17, 34,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_SHOT_DOWN].CreateSprite(		SpriteHandler, BODY_SHOT_DOWN_FILE,			SPRITEWIDTH, SPRITEHEIGHT, 7, 14,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_SHOT].CreateSprite(				SpriteHandler, BODY_SHOT_FILE,				SPRITEWIDTH, SPRITEHEIGHT, 10, 20,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_SHOT_UP].CreateSprite(			SpriteHandler, BODY_SHOT_UP_FILE,			SPRITEWIDTH, SPRITEHEIGHT, 18, 36,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_SLEEP].CreateSprite(			SpriteHandler, BODY_SLEEP_FILE,				SPRITEWIDTH, SPRITEHEIGHT, 10, 20,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_STAND].CreateSprite(			SpriteHandler, BODY_STAND_FILE,				SPRITEWIDTH, SPRITEHEIGHT, 4, 8,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_THROW_GRENADE].CreateSprite(	SpriteHandler, BODY_THROW_GRENADE_FILE,		SPRITEWIDTH, SPRITEHEIGHT, 5, 20,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	m_Sprite[BODY_TIRED].CreateSprite(			SpriteHandler, BODY_TIRED_FILE,				SPRITEWIDTH, SPRITEHEIGHT, 18, 36,	mf_Scale, D3DCOLOR_XRGB(255,255,255));

	Marco_Leg[0].CreateSprite(SpriteHandler, NULL, 1, 1, 1, 1, 1, 0);
	Marco_Leg[LEG_JUMP_FAR].CreateSprite(	SpriteHandler, LEG_JUMP_FAR_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 6, 12,	mf_Scale, D3DCOLOR_XRGB(255,255,255)); 
	Marco_Leg[LEG_JUMP_UP].CreateSprite(	SpriteHandler, LEG_JUMP_UP_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 1, 2,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	Marco_Leg[LEG_RUN].CreateSprite(		SpriteHandler, LEG_RUN_FILE,		SPRITEWIDTH, SPRITEHEIGHT, 18, 36,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
	Marco_Leg[LEG_STAND].CreateSprite(		SpriteHandler, LEG_STAND_ON_FILE,	SPRITEWIDTH, SPRITEHEIGHT, 1, 2,	mf_Scale, D3DCOLOR_XRGB(255,255,255));
}

//update method
//
void CMarco::update(int DeltaTime, int moveCame)
{
		m_nAndr += mf_vx*DeltaTime;

	 if (m_nAndr < 10)
		 m_nAndr = 10;

	 if(m_nAndr > 2810)
		 m_nAndr = 2810;


	m_nposX = m_nAndr - moveCame;
	m_nposY += mf_vy*DeltaTime;

	setRect();

	for(int i = 0; i < m_varrayBullets.size(); i++)
	{
		if (m_nAndr < 350)
		{
			if(m_varrayBullets[i]->m_nAndr > 800)
			{
				m_varrayBullets.erase(m_varrayBullets.begin() + i);
				i--;
			}
		}
		else
		{
			if(m_varrayBullets[i]->m_nAndr > m_nAndr + 400)
			{
				m_varrayBullets.erase(m_varrayBullets.begin() + i);
				i--;
			}
		}
	}

	for(int i = 0; i < m_varrayBullets.size(); i++)
		m_varrayBullets[i]->Update(DeltaTime, moveCame);

	//if character still jumping
	if (m_nposY < GROUND)
	{
		mf_vy += 0.2;
	}

	else if (m_nposY > GROUND)
	{
		mf_vy = 0;
		mf_vx = 0;
		m_nposY = GROUND;
		mb_IsJump = false;
	}

	DWORD dw_now = GetTickCount();

	DeltaTime = dw_now - mdw_LastTime;

	if ((DeltaTime) >= (1000/mi_AnimateRate))
	{
		next();
		mdw_LastTime = dw_now;
	}

	if (!mb_IsAction)
	{
		mi_AnimateRate = FPS_STAND;
	}
}

void CMarco::SetDirection(int iDirection)
{
	mi_Direction = iDirection;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);
	Marco_Leg[mi_LegIndex].SetSpriteLine(mi_Direction);
}
//method to render character 
//
void CMarco::Reset()
{
	m_Sprite[mi_BodyIndex].Reset();
	Marco_Leg[mi_LegIndex].Reset();
}

void CMarco::next()
{
	m_Sprite[mi_BodyIndex].Next();
	Marco_Leg[mi_LegIndex].Next();

	if ((mi_BodyIndex == BODY_SHOT)&&(mb_ShotContinue))
	{
		if (m_Sprite[mi_BodyIndex].GetIndex() == 6)
		{
			m_Sprite[mi_BodyIndex].SetIndex(0);
			mb_ShotContinue = false;
		}
	}

	if ( m_Sprite[mi_BodyIndex].GetIndex() == m_Sprite[mi_BodyIndex].GetPerRow() - 1 )
	{		
		if (mi_BodyIndex == BODY_SLEEP)
		{
			m_Sprite[mi_BodyIndex].SetIndex(3);
		}
		else  if (mi_BodyIndex == BODY_JUMP_UP)
		{
			m_Sprite[mi_BodyIndex].SetIndex(5);
		}
		else if (mi_BodyIndex == BODY_JUMP_FAR)
		{
			m_Sprite[mi_BodyIndex].SetIndex(5);
			Marco_Leg[mi_LegIndex].SetIndex(5);
		}
		else
		{
			mb_IsAction = false;
			mb_IsRelax = false;
		}
	}

}

void CMarco::setRect()
{
	m_ObRect = new RECT();
	m_ObRect->left = m_nAndr;
	m_ObRect->right = m_ObRect->left + X;
	m_ObRect->top = m_nposY;
	m_ObRect->bottom = m_ObRect->top + Y;
}

void CMarco::render()
{
	int iBodyX	= m_nposX - mf_Scale*X;
	int iBodyY	= m_nposY;
	for( int i = 0; i < m_varrayBullets.size(); i++)
	{
		m_varrayBullets[i]->Render();
	}
	Marco_Leg[mi_LegIndex].Render(iBodyX, iBodyY);
	m_Sprite[mi_BodyIndex].Render(iBodyX, iBodyY);

}

//Method to makes character move
//
void CMarco::Run(int iDirection)
{
	mi_Direction = iDirection;

	if (mi_Direction == LEFT)
	{
		mf_vx = -VERLOCITY_X_RUN;
	}

	else
	{
		mf_vx = VERLOCITY_X_RUN;
	}

	mf_vy = 0;

	if (!mb_IsAction)
	{
		mi_BodyIndex	 = BODY_RUN;	
	}

	mi_LegIndex		 = LEG_RUN;

	mi_AnimateRate = FPS_ACTION;

	mb_IsRelax = false;

	Marco_Leg[mi_LegIndex].SetSpriteLine(mi_Direction);
	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);	
}

void CMarco::Stand()
{
	mi_LegIndex		= LEG_STAND;

	if ((!mb_IsAction)&&(!mb_IsRelax))
	{
		mi_BodyIndex	= BODY_STAND;	
	}		

	Marco_Leg[mi_LegIndex].SetSpriteLine(mi_Direction);
	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);	

	mf_vx = 0;
	mf_vy = 0;
}

void CMarco::Crouch()
{
	if (!mb_IsAction)
	{
		mi_BodyIndex = BODY_CROUCH;
	}
	mi_LegIndex = NULL;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	mf_vx = 0;
	mf_vy = 0;
	mb_IsRelax = false;
}

void CMarco::CrouchMove(int iDirection)
{
	mi_BodyIndex = BODY_CROUCH_MOVE;
	mi_LegIndex = NULL;

	mi_Direction = iDirection;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	if (iDirection == LEFT)
	{
		mf_vx = -VERLOCITY_X_CROUCH_MOVE;
	}
	else
	{
		mf_vx = VERLOCITY_X_CROUCH_MOVE;
	}
	mf_vy = 0;

	mi_AnimateRate = FPS_ACTION;
	mb_IsRelax = false;
}

void CMarco::JumpUp()
{
	mf_vx = 0;
	mf_vy = VERLOCITY_Y_JUMP;

	mi_BodyIndex = BODY_JUMP_UP;
	mi_LegIndex = LEG_JUMP_UP;

	mi_AnimateRate = FPS_JUMP;

	mb_IsJump = true;
	mb_IsRelax = false;
	Reset(); 

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);
	Marco_Leg[mi_LegIndex].SetSpriteLine(mi_Direction);
}

void CMarco::JumpFar(int iDirection)
{
	mi_BodyIndex = BODY_JUMP_FAR;
	mi_LegIndex = LEG_JUMP_FAR;
	mi_Direction = iDirection;

	if (mi_Direction == LEFT)
		mf_vx = -VERLOCITY_X_JUMP_FAR;
	else
		mf_vx = VERLOCITY_X_JUMP_FAR;
	mf_vy = VERLOCITY_Y_JUMP;

	mi_AnimateRate = FPS_JUMP;

	mb_IsJump = true;

	Reset(); 

	SetDirection(iDirection);
}


//methods to make character action
//
void CMarco::Shot()
{
	m_nbulletIndex++;	

	/*char str[25];
	itoa(m_nbulletIndex, str, 10);
	if(m_nbulletIndex ==3 )
		MessageBox(NULL, str , "Error", MB_OK); */

	if(m_nbulletIndex == BULLET_TOTAL)
	{
		m_nbulletIndex = 0;
	}

	if (m_varrayBullets.size() < BULLET_TOTAL)
		m_varrayBullets.push_back(Bullet[m_nbulletIndex]); 
	
	mi_BodyIndex	 = BODY_SHOT;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);
	m_Sprite[mi_BodyIndex].Reset();
	Bullet[m_nbulletIndex]->m_nAndr = m_nAndr + SPRITEWIDTH - 7*2;
	Bullet[m_nbulletIndex]->m_nposY = m_nposY + 15*7;
	Bullet[m_nbulletIndex]->bullet();

	mb_IsAction = true;
	mb_IsRelax = false;
	mb_isShot[m_nbulletIndex] = true;
	mi_AnimateRate = FPS_ACTION;
}

void CMarco::ShotUp()
{
	mi_BodyIndex = BODY_SHOT_UP;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	mi_AnimateRate = FPS_ACTION;

	mb_IsAction = true;
	mb_IsRelax = false;
}

void CMarco::ShotDown()
{
	mi_BodyIndex = BODY_SHOT_DOWN;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	mi_AnimateRate = FPS_ACTION;

	mb_IsAction = true;
	mb_IsRelax = false;
}

void CMarco::CrouchShot(void)
{
	mi_BodyIndex = BODY_CROUCH_SHOT;
	mi_LegIndex  = NULL;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	mf_vx = mf_vy = 0;

	mi_AnimateRate = FPS_ACTION;

	mb_IsAction = true;
	mb_IsRelax = false;
}

void CMarco::ThrowGrenade()
{
	mi_BodyIndex = BODY_THROW_GRENADE;

	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	mb_IsAction = true;
	mb_IsRelax = false;
	mi_AnimateRate = FPS_ACTION;
}


//method to makes character relax
//
void CMarco::Relax()
{	
	int iRange = (RELAX_END_INDEX - RELAX_START_INDEX) +1;
	int iRelaxIndex;

	iRelaxIndex = RELAX_START_INDEX + int (iRange*rand()/(RAND_MAX + 1.0 ));

	mi_BodyIndex = iRelaxIndex;
	m_Sprite[mi_BodyIndex].SetSpriteLine(mi_Direction);

	mb_IsRelax = true;
	mi_AnimateRate = FPS_ACTION;
}

//set methods
//

void CMarco::setX(int ix)
{
	m_nposX = ix;
}

void CMarco::setY(int iy)
{
	m_nposY = iy;
}

void CMarco::setVerlocityX(float fx)
{
	mf_vx = fx;
}

void CMarco::setVerlocityY(float fy)
{
	mf_vy = fy;
}

//get methods
//
int CMarco::GetBodyIndex()
{
	return m_Sprite[mi_BodyIndex].GetIndex();
}

bool CMarco::IsAction(void)
{
	return mb_IsAction;
}

bool CMarco::IsRelax(void)
{
	return mb_IsRelax;
}

bool CMarco::IsJump(void)
{
	return mb_IsJump;
}

bool CMarco::IsShot()
{
	return mb_isShot;
}